/* 
 * File:   InsertTable.cpp
 * Author: vikrantsingh
 * 
 * Created on 2 November, 2013, 9:58 PM
 */

#include "InsertTable.h"
#include "Validation.h"
#include "../Sysfiles/SysCatalog.h"
#include "../PageLayout/Tuple.h"
#include "SelectTable.h"
#include"../Utils/Timer.h"
#include "../IndexManager/BPlusTree.h"
#include "../dependency/util.h"
#include "../IndexManager/IndexUtil.h"

InsertTable::InsertTable() {
}

InsertTable::InsertTable(const InsertTable& orig) {
}

InsertTable::~InsertTable() {
}

STATUS_CODE InsertTable::run(QueryStructures *queryStruct) {
//    Timer timer;
//    timer.startTimer();
    //DEBUG("inside insertTable execute");
    int err = Validation::isValid();
    if (err != SUCCESS) {
        return err;
    }
    SysCatalog cat;
    Schema schema;
    err = cat.getSchema(queryStruct->tableName.c_str(), schema);
    if (err == TABLE_NOT_FOUND) {
        return err;
    }
    //insert into first values (10); queries like this col is not specified
    if (queryStruct->insertValues.size() != (unsigned int) schema.numOfColumns) {
        return PARSE_FAILED;
    }

    Heap heapFile(queryStruct->tableName.c_str());
    for (unsigned int i = 0; i < queryStruct->insertValues.size(); i++) {
        DEBUG("insertValue[" << i << "]=" << queryStruct->insertValues[i]);
    }

    Tuple tuple(schema, queryStruct->insertValues);
    char *record = tuple.recordPreparation();
    for (int i = 0; i < tuple.getLength(); i++) {
        DEBUG("record after prep" << record[i]);
    }
    RIDStruct rid;
    err = heapFile.insertRecord(rid, tuple.getLength(), record);
    if (SUCCESS != err) {
        return err;
    }
    int numOfRecords = heapFile.getNoOfRecords();
    if (numOfRecords % 5000 == 0) {
        std::cout << "NUM OF RECORDS INSERTED=" << numOfRecords << endl;
    }
   // if (USING_INDEX == true) {
     if (true) {

//        cout<<"using index";
        int tableID;
        cat.getTableId(schema.tableName.c_str(), tableID);
        SelectTable select;
        QueryStructures toGetFromSysIndex;
        toGetFromSysIndex.resultSetColumnList.push_back("INDEX_ID");
        toGetFromSysIndex.resultSetColumnList.push_back("INDEX_HDR_PG_NO");
        toGetFromSysIndex.tableName = "SYSINDEX";
        WhereClause exprInfo1(WhereClause::IDENTIFIER_TYPE, "TAB_ID");
        WhereClause exprInfo2(WhereClause::LITERAL_TYPE, Util::int_to_string(tableID));
        WhereClause exprInfo3(WhereClause::OPERATOR_TYPE, "=");
        toGetFromSysIndex.whereConditionExprList.push_back(exprInfo1);
        toGetFromSysIndex.whereConditionExprList.push_back(exprInfo2);
        toGetFromSysIndex.whereConditionExprList.push_back(exprInfo3);
        err = select.fetchResultSetAll_WithoutIndex(&toGetFromSysIndex);
        if (SUCCESS != err) {
            return err;
        }
        for (unsigned i = 0; i < select.resultSet.size(); i++) {
//            cout<<"\ninside for result set size"<<select.resultSet.size();
            SelectTable selectQuerytoGetFromSysIndexCol;
            QueryStructures toGetFromSysIndexCol;
            toGetFromSysIndexCol.resultSetColumnList.push_back("SYS_COL_ID");
            toGetFromSysIndexCol.tableName = "SYSINDEXCOL";
            WhereClause exprInfo1(WhereClause::IDENTIFIER_TYPE, "INDEX_ID");
            WhereClause exprInfo2(WhereClause::LITERAL_TYPE, select.resultSet[i].getFeildInString("INDEX_ID"));
            WhereClause exprInfo3(WhereClause::OPERATOR_TYPE, "=");
            toGetFromSysIndexCol.whereConditionExprList.push_back(exprInfo1);
            toGetFromSysIndexCol.whereConditionExprList.push_back(exprInfo2);
            toGetFromSysIndexCol.whereConditionExprList.push_back(exprInfo3);
            err = selectQuerytoGetFromSysIndexCol.fetchResultSetAll_WithoutIndex(&toGetFromSysIndexCol);
            if (SUCCESS != err) {
                return err;
            }
            
//            cout<<"\n num of col"<<selectQuerytoGetFromSysIndexCol.resultSet.size()<<endl;
            int indexHeaderPageNum = Util::string_to_int(select.resultSet[i].getFeildInString("INDEX_HDR_PG_NO"));                        
            IndexHeaderPage indexHeaderPage(indexHeaderPageNum);
//            cout<<"INSERT INTO INDEX HEADER PAGE NUM"<<indexHeaderPageNum<<endl;
            
            int keySize = indexHeaderPage.getKeySize();
            
            char *keyData = new char[keySize];
            vector<int> colIds;
            for(unsigned l=0;l<selectQuerytoGetFromSysIndexCol.resultSet.size();l++){
                colIds.push_back(Util::string_to_int(selectQuerytoGetFromSysIndexCol.resultSet[l].getFeildInString("SYS_COL_ID")));
            }
            
            tuple.getKeyData(colIds, keyData);
//            cout<<"keyData:"<<IndexUtil::keyToString(keyData,&indexHeaderPage)<<endl;
//            cout<<"INSERT INTO INDEX HEADER PAGE NUM"<<indexHeaderPageNum<<endl;
            BPlusTree bplusTree(indexHeaderPageNum);
            
//            cout<<"\nRID="<<rid.toString();
            bplusTree.insert(keyData, rid);
            
            delete keyData;
        }


    }

//    timer.updateNumberOfRows(numOfRecords);
//    timer.endTimer();
//    std::string elapsedTime = timer.getElapsedTimeInMilliSeconds();
//    elapsedTime.append("  milliseconds");
//    timer.updateExecutionTimeMessage(elapsedTime);
    return SUCCESS;
}